package org.six11.olive.collabclient.server;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.filter.ElementFilter;
import org.jdom.filter.Filter;
import org.jdom.input.SAXBuilder;
import org.six11.util.io.Message;
import org.six11.util.Debug;
import org.six11.util.adt.MultiState;

/**
 * 
 * 
 * @author Gabe Johnson <johnsogg@cmu.edu>
 */
public class Router extends HttpServlet {

  private Filter msgFilter;

  public Router() {
    super();
    this.msgFilter = new ElementFilter("msg");
  }

  public MultiState getState() {
    MultiState state = (MultiState) getServletConfig().getServletContext().getAttribute("state");
    if (state == null) {
      important("value for state not found");
    }
    return state;
  }

  @SuppressWarnings("unchecked")
  public Map<String, WebActionHandler> getWebHandlers() {
    Map<String, WebActionHandler> h = (Map<String, WebActionHandler>) getState().getValue(
        "webHandlers");
    if (h == null) {
      important("value for webHandlers not found");
    }
    return h;
  }

  @SuppressWarnings("unchecked")
  public Map<String, AppletMessageHandler> getAppletHandlers() {
    Map<String, AppletMessageHandler> h = (Map<String, AppletMessageHandler>) getState().getValue(
        "appletHandlers");
    if (h == null) {
      important("value for appletHandlers not found");
    }
    return h;
  }

  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
      IOException {
    String what = req.getParameter(WebActionHandler.ACTION);
    if (what == null || what.equals("")) {
      what = "index";
    }
    Map<String, WebActionHandler> webActionHandlers = getWebHandlers();

    if (webActionHandlers.containsKey(what)) {
      webActionHandlers.get(what).handle(req, resp, getServletContext());
    } else {
      important("Bogus web action request for action '" + what + "'");
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
      IOException {

    // the web pages hit the path '/web'. This should be handled by the doGet method but some
    // forms (especially those involving passwords) send data up via POST. But the doGet can parse
    // those parameters anyway.
    if (req.getServletPath().equals("/web")) {
      doGet(req, resp);
      return;
    }
    HttpSession session = req.getSession();

    PrintWriter out = resp.getWriter();
    InputStream in = req.getInputStream();
    try {
      Document msgDoc = new SAXBuilder().build(in);
      List msgList = msgDoc.getRootElement().getContent(msgFilter);
      if (msgList.isEmpty()) {
        bug("User connected but did not send any messages.");
      }
      for (Object msgObj : msgList) {
        Element elm = (Element) ((Element) msgObj).clone();
        elm.detach();
        Message msg = new Message(elm);
        Map<String, AppletMessageHandler> appletMessageHandlers = getAppletHandlers();
        if (appletMessageHandlers.containsKey(msg.getType())) {
          appletMessageHandlers.get(msg.getType()).handle(msg, session.getId(), out);
        } else {
          important("No applet message handler found for message type: " + msg.getType());
        }
      }
    } catch (JDOMException ex) {
      ex.printStackTrace();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private void bug(String what) {
    Debug.out("Router", what);
  }

  private void important(String what) {
    Debug.out(">>  Router", what);
  }

  @Override
  public void destroy() {
    super.destroy();
    // TODO: leaving this in as a reminder that timers should be stopped when the servlet dies.
    // Timer timer = (Timer) state.getValue(ServerStateNames.TASK_TIMER);
    // timer.cancel();
    // important("Stopped task timer.");
  }
}
